package com.wendy.config;

import com.wendy.authentication.*;
import com.wendy.thirdpartyaccess.qq.QQAuthenticationFilter;
import com.wendy.thirdpartyaccess.qq.QQAuthenticationManager;
import com.wendy.utils.AlgorithmUtil;
import com.wendy.utils.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @author zhuwending
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserFilterSecurityInterceptor filterSecurityInterceptor;
    @Autowired
    private UserAuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    private UserAuthenticationFailHandler authenticationFailHandler;

    @Autowired
    private UserAccessDeniedHandler accessDeniedHandler;

    @Bean
    UserDetailsService customerUserService() {
        return new UserDetailsServiceImpl();
    }

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Override
    protected void configure(HttpSecurity security) throws Exception {
        security.csrf().disable();
        //允许同源的iframe页面嵌套
        security.headers().frameOptions().sameOrigin();
        security.authorizeRequests().anyRequest().permitAll();
        security.authorizeRequests()
                .anyRequest().authenticated().antMatchers("/page/404", "page/500", "/page/403").permitAll()
                .and().formLogin().loginPage(Constants.LOGIN_PAGE).loginProcessingUrl(Constants.LOGIN_URI).permitAll()
                .successHandler(authenticationSuccessHandler).failureHandler(authenticationFailHandler)
                .and().sessionManagement().maximumSessions(1).expiredUrl("/page/login").and().invalidSessionUrl("/page/login")
                .and().logout().logoutUrl("/logout").logoutSuccessUrl("/page/login").deleteCookies("JSESSIONID").permitAll();
        security.addFilterBefore(filterSecurityInterceptor, FilterSecurityInterceptor.class).addFilterAt(qqAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        security.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    }

    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.userDetailsService(customerUserService()).passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/**");
        web.expressionHandler(expressionHandler());
        super.configure(web);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return AlgorithmUtil.md5((String) charSequence);
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return AlgorithmUtil.md5((String) charSequence).equals(s);
            }
        };
    }


    private SecurityExpressionHandler<FilterInvocation> expressionHandler() {
        DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
        expressionHandler.setDefaultRolePrefix("");
        return expressionHandler;
    }

    private QQAuthenticationFilter qqAuthenticationFilter() {
        QQAuthenticationFilter filter = new QQAuthenticationFilter("/login/qq");
        filter.setAuthenticationManager(new QQAuthenticationManager());
        return filter;
    }
}
